package com.wyl.auth.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.net.PassAuth;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.wyl.auth.config.security.SecurityUser;
import com.wyl.auth.dto.SysUserDto;
import com.wyl.auth.dto.SysUserRoleDto;
import com.wyl.auth.entity.SysMenu;
import com.wyl.auth.entity.SysRole;
import com.wyl.auth.entity.SysUser;
import com.wyl.auth.entity.SysUserRole;
import com.wyl.auth.excel.SysUserExport;
import com.wyl.auth.exception.BusinessException;
import com.wyl.auth.mapper.SysUserMapper;
import com.wyl.auth.req.ResetPasswordReq;
import com.wyl.auth.req.SysUserReq;
import com.wyl.auth.service.SysMenuService;
import com.wyl.auth.service.SysRoleService;
import com.wyl.auth.service.SysUserRoleService;
import com.wyl.auth.service.SysUserService;
import com.wyl.auth.util.BeanAwareUtil;
import com.wyl.auth.vo.CurrentUserVo;
import com.wyl.auth.vo.SysUserVo;
import com.wyl.auth.vo.UserPermissionVo;
import com.wyl.common.CommonPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.security.util.Password;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
* @Description 系统用户
* @Author WuYiLong
* @Date 2024-12-21
*/
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private ExportService exportService;

    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SysRoleService sysRoleService;

    @Override
    public SysUserVo getByUsername(String username) {
        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getUsername, username);
        SysUser sysUser = getOne(wrapper);
        SysUserVo sysUserVo = BeanUtil.copyProperties(sysUser, SysUserVo.class);
        return sysUserVo;
    }

    @Override
    public void saveUser(SysUserDto sysUserDto) {
        if(sysUserDto.getId() != null) {
            SysUser sysUser = baseMapper.selectById(sysUserDto.getId());
            BeanAwareUtil.copyProperties(sysUserDto, sysUser);
            sysUser.setUpdateTime(LocalDateTime.now());
            sysUser.updateById();
        }else{
            SysUser sysUser = new SysUser();
            BeanAwareUtil.copyProperties(sysUserDto, sysUser);
            String hashpw = BCrypt.hashpw(sysUserDto.getPassword(), BCrypt.gensalt());
            sysUser.setPassword(hashpw);
            sysUser.setUpdateTime(LocalDateTime.now());
            sysUser.setCreateTime(LocalDateTime.now());
            sysUser.insert();
        }
    }

    @Override
    public CommonPage<SysUserVo> pageUser(SysUserReq sysUserReq) {
        Page<SysUser> sysUserPage = new Page<>(sysUserReq.getCurrentPage(), sysUserReq.getPageSize());
        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StrUtil.isNotBlank(sysUserReq.getUsername()), SysUser::getUsername, sysUserReq.getUsername());
        wrapper.like(StrUtil.isNotBlank(sysUserReq.getPhone()),SysUser::getPhone,sysUserReq.getPhone());
        wrapper.like(StrUtil.isNotBlank(sysUserReq.getEmail()),SysUser::getEmail,sysUserReq.getEmail());
        wrapper.orderByDesc(SysUser::getCreateTime);
        Page<SysUser> page = baseMapper.selectPage(sysUserPage, wrapper);

        List<SysUserVo> sysUserVos = page.getRecords().stream()
                .map(m -> {
                    SysUserVo sysUserVo = BeanUtil.copyProperties(m, SysUserVo.class);
                    createSysUserVo(m.getId(), sysUserVo);
                    return sysUserVo;
                }).collect(Collectors.toList());

        CommonPage<SysUserVo> commonPage = new CommonPage<>();
        commonPage.setCurrentPage(sysUserReq.getCurrentPage());
        commonPage.setPageSize(sysUserReq.getPageSize());
        commonPage.setList(sysUserVos);
        commonPage.setTotal((int)page.getTotal());
        return commonPage;
    }


    private void createSysUserVo(Long userId, SysUserVo sysUserVo) {
        List<SysUserRole> sysUserRoles = sysUserRoleService.getByUserId(userId);
        List<Long> roleIds = sysUserRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        List<SysRole> sysRoles = sysRoleService.listByIds(roleIds);
        String roleName = sysRoles.stream().map(SysRole::getName).collect(Collectors.joining(","));
        sysUserVo.setRoleName(roleName);
    }

    @Override
    public void deleteUserByIds(List<Long> ids) {
        baseMapper.deleteBatchIds(ids);
    }

    @Override
    public void exportUser(SysUserReq sysUserReq, HttpServletResponse response) {
        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery();
        if(CollUtil.isNotEmpty(sysUserReq.getIds())) {
            wrapper.in(SysUser::getId, sysUserReq.getIds());
        }
        wrapper.like(StrUtil.isNotBlank(sysUserReq.getUsername()), SysUser::getUsername, sysUserReq.getUsername());
        wrapper.like(StrUtil.isNotBlank(sysUserReq.getPhone()),SysUser::getPhone,sysUserReq.getPhone());
        wrapper.like(StrUtil.isNotBlank(sysUserReq.getEmail()),SysUser::getEmail,sysUserReq.getEmail());
        wrapper.orderByDesc(SysUser::getCreateTime);
        List<SysUser> sysUsers = baseMapper.selectList(wrapper);

        List<SysUserExport> sysUserExports = sysUsers.stream().map(m -> {
            SysUserExport sysUserExport = new SysUserExport();
            BeanAwareUtil.copyProperties(m, sysUserExport);
            return sysUserExport;
        }).collect(Collectors.toList());

        exportService.initResponse(response,"用户");
        exportService.exportExcel(sysUserExports,SysUserExport.class,response);
    }

    @Override
    public String resetPassword(Long id) {
        SysUser sysUser = baseMapper.selectById(id);
        String randomNumber = RandomUtil.randomString(6);
        sysUser.setPassword(BCrypt.hashpw(randomNumber,BCrypt.gensalt()));
        sysUser.updateById();
        return randomNumber;
    }

    @Override
    public CurrentUserVo getCurrentUser() {
        long userId = StpUtil.getLoginIdAsLong();
        SysUser sysUser = baseMapper.selectById(userId);
        CurrentUserVo securityUserVo = new CurrentUserVo();
        securityUserVo.setUsername(sysUser.getUsername());
        securityUserVo.setUserId(userId);
        securityUserVo.setAvatar(sysUser.getAvatar());
        securityUserVo.setEmail(sysUser.getEmail());
        securityUserVo.setPhone(sysUser.getPhone());
        securityUserVo.setCreateTime(sysUser.getCreateTime());
        securityUserVo.setSex(sysUser.getSex());
        List<Tree<Long>> trees = sysMenuService.treeSysMenu();
        securityUserVo.setMenuTrees(trees);
        List<Long> menuIds = sysMenuService.getMenuIdsByUserId();
        if(CollUtil.isNotEmpty(menuIds)) {
            List<SysMenu> sysMenus = sysMenuService.listByIds(menuIds);
            List<String> menuCodes = sysMenus.stream().map(SysMenu::getCode).collect(Collectors.toList());
            securityUserVo.setMenuCodes(menuCodes);

        }
        List<SysUserRole> sysUserRoles = sysUserRoleService.getByUserId(userId);
        if(CollUtil.isNotEmpty(sysUserRoles)) {
            List<Long> roleIds = sysUserRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
            List<SysRole> sysRoles = sysRoleService.listByIds(roleIds);
            List<UserPermissionVo.Role> collect = sysRoles.stream().map(m -> {
                UserPermissionVo.Role role = new UserPermissionVo.Role();
                role.setRoleCode(m.getCode());
                role.setRoleName(m.getName());
                return role;
            }).collect(Collectors.toList());

            securityUserVo.setRole(collect);
        }
        return securityUserVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void assignRole(SysUserRoleDto dto) {
        LambdaQueryWrapper<SysUserRole> sysUserRoleLambdaQueryWrapper = Wrappers.lambdaQuery(SysUserRole.class);
        sysUserRoleLambdaQueryWrapper.eq(SysUserRole::getUserId, dto.getUserId());
        sysUserRoleService.remove(sysUserRoleLambdaQueryWrapper);

        List<Long> roleIds = dto.getRoleIds();
        for (Long roleId : roleIds) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(dto.getUserId());
            sysUserRole.setRoleId(roleId);
            sysUserRoleService.save(sysUserRole);
        }
    }

    @Override
    public List<Long> listRolesByUserId(Long userId) {
        LambdaQueryWrapper<SysUserRole> sysUserRoleLambdaQueryWrapper = Wrappers.lambdaQuery(SysUserRole.class);
        sysUserRoleLambdaQueryWrapper.eq(SysUserRole::getUserId, userId);
        List<SysUserRole> list = sysUserRoleService.list(sysUserRoleLambdaQueryWrapper);
        List<Long> roleIds = list.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        return roleIds;
    }

    @Override
    public void resetPassword(ResetPasswordReq req) {
        SysUser sysUser = getById(req.getUserId());
        if(!BCrypt.checkpw(req.getPassword(), sysUser.getPassword())) {
            throw new BusinessException("密码错误");
        }
        String newPassword = BCrypt.hashpw(req.getNewPassword(), BCrypt.gensalt());
        sysUser.setPassword(newPassword);
        sysUser.updateById();
    }
}
